package org.wangduqing.ibatisdao.hibernate.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.wangduqing.ibatisdao.hibernate.dao.IGenericBaseCommonDao;

@Component
@Transactional
public class GenericBaseCommonDao implements IGenericBaseCommonDao {
	
	private static final Logger logger = Logger.getLogger(GenericBaseCommonDao.class);
	
	private SessionFactory sessionFactory;

	@Override
	public <T> void save(T entity) {
		
		try {
			Session session = getSession();
			session.save(entity);
			session.flush();
			if(logger.isDebugEnabled()){
				
				logger.debug("保存实体成功," + entity.getClass().getName());
				
			}
		} catch (RuntimeException e) {
			
			logger.error("保存实体异常", e);
			throw e;
			
		}
	}

	@Override
	public <T> void saveOrUpdata(T entity) {
		
		try {
			
			Session session = getSession();
		    
			session.update(entity);
			session.flush();
			if(logger.isDebugEnabled()){
				
				logger.debug("添加或更新成功," + entity.getClass().getName());
				
			}
			
		} catch (RuntimeException e) {
			
			logger.error("添加或更新异常", e);
			throw e;
			
		}

	}

	@Override
	public <T> void delete(T entitie) {
		
		try {
			
			getSession().delete(entitie);
			getSession().flush();
			if(logger.isDebugEnabled()){
				
				logger.debug("删除成功," + entitie.getClass().getName());
				
			}
		} catch (HibernateException e) {
			
			logger.error("删除异常", e);
			throw e;
			
		}

	}

	@Override
	public <T> T get(T entitie) {
		
		Criteria executableCriteria = getSession().createCriteria(entitie.getClass());
		executableCriteria.add(Example.create(entitie));
		if(executableCriteria.list().size()==0){

			return null;
			
		}
		return (T) executableCriteria.list().get(0);
		
	}
	
	private <T> Criteria createCriteria(Class<T> entityClass, boolean isAsc, Criterion...criterions){
		
		Criteria criteria = createCriteria(entityClass, criterions);
		if(isAsc){
			
			criteria.addOrder(Order.asc("asc"));
			
		}else{
			
			criteria.addOrder(Order.desc("desc"));
			
		}
		return criteria;
		
	}
	
	private <T> Criteria createCriteria(Class<T> entityClass, Criterion...criterions){
		
		Criteria criteria = getSession().createCriteria(entityClass);
		for(Criterion c:criterions){
			
			criteria.add(c);
			
		}
		return criteria;
		
	}

	@Override
	public <T> List<T> loadAll(T entitie) {

		Criteria executableCriteria = getSession().createCriteria(entitie.getClass());
		executableCriteria.add(Example.create(entitie));
		return executableCriteria.list();
		
	}

	@Override
	public <T> T get(Class<T> entityClass, Serializable id) {
		
		return (T) getSession().get(entityClass, id);
		
	}

	@Override
	public Session getSession() {

		try {
			
			return sessionFactory.getCurrentSession();
			
		} catch (Exception e) {
			
			return sessionFactory.openSession();
			
		}
	}

	@Override
	public <T> T findUniqueByProperty(Class<T> entityClass,
			String propertyName, Object value) {
		
		Assert.hasText(propertyName);
		return  (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
	}
	
	public <T> List<T> findByProperty(Class<T> entityClass, String propertyName, Object value){
		
		Assert.hasText(propertyName);
		return (List<T>) createCriteria(entityClass, Restrictions.eq(propertyName, value)).list();
		
	}

	@Override
	public <T> void deleteEntityById(Class<T> entityClass, Serializable id) {
		
		delete(get(entityClass, id));
		getSession().flush();

	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
}
